#include <QSqlQuery>
#include <QSqlError>
#include "statusoperation.h"
#include "dialog.h"
#include "ui_dialog.h"
#include "DBO/db.h"
#include "macro.h"
//#include "protocolconversion.h"
#include "P2P/p2pserver.h"
#include "ONSClient/onsmessenger.h"
#include "DBO/dbointhread.h"
#include "DBO/protocolconversion.h"
#if (WIN32)
#include "windows.h"
#else
//linux here
#include <unistd.h>
#endif
#include <QThread>
//#define DEBUG

StatusOperation::StatusOperation(QObject *parent) :
    QObject(parent)
{
    parentWeathSta=(WeatherStation*)parent;
    timer=new QTimer(this);
    connect(timer,SIGNAL(timeout()),this,SLOT(myTimerEvent()));
    timerForTTL=new QTimer(this);
    timerForTTL->start(20000); //20s一次
    connect(timerForTTL,SIGNAL(timeout()),this,SLOT(timerEventForTTL()));

    initTableNameList();
    initTimer();

}

void    StatusOperation::analyNodeInfoPacket(QByteArray &data, qint64 macAddr)
{
    bool    ok;
    quint8 dataType;
    parentWeathSta->slotShowErrorInfo(tr("正在处理节点信息包..."));
    while(data.size()>=2)
    {
        dataType=data.mid(0,1).toHex().toUShort(&ok,16);
        data.remove(0,1);
        switch(dataType)
        {
            case    NodeInfoMac: //Mac地址
                parentWeathSta->slotShowErrorInfo(tr("处理mac地址信息..."));

                if(data.size()<macBytes)
                    return;
                macAddr=data.mid(0,macBytes).toHex().toULongLong(&ok,16);
                if(addrTTLMap.contains(macAddr)) //如果这个节点还处于连接状态
                {
                    data.remove(0,macBytes);
                    break;
                }
                else
                {
                    doWithMac(macAddr);
                    data.remove(0,macBytes);
                    break;
                }
            case    NodeInfoSensors:  //节点上的传感器类型
                if(data.size()<NodeInfoSensorTypeBytes)
                    return;
                parentWeathSta->slotShowErrorInfo(tr("处理传感器类型信息..."));
                doWithSensorInfo(data,macAddr);
                data.remove(0,NodeInfoSensorTypeBytes);
                break;

        }
    }
}


/*
 对心跳包进行处理。如果对应的连接没有断，则更新TTL值，返回true。否则，返回false。
 */
bool    StatusOperation::analyHeartPakcet(QByteArray &data, qint64 parMacAddr)
{
    if(sourceV4IP.count(".")!=3)
        return false;
    qint64 macAddr=addrSocketMap.key(sourceV4IP+":"+QString::number(sourcePort));
    if(data.size()<2)
        return false;

    if(macAddr==parMacAddr) //如果能找到这一项
    {
        updateAddrTTLMap(macAddr,TTL_MAX);
        return true;
    }
    else
    {
        doWithMac(parMacAddr);
        return true;  //如果没有这一项，说明可能是因为连接断开了，对应的信息已经被清除
    }
}

void StatusOperation::analyQuerySensorInfo(QByteArray &data, qint64 paramMacAddr)
{
    bool ok;
    if(data.size()<2)
        return;
    quint8 dataType=data.mid(0,1).toHex().toUShort(&ok,16);
    quint8 dataInIt=data.mid(1,1).toHex().toUShort(&ok,16);

    if(dataType==SensorInfoSensorTypeAllSensors&&dataInIt==SensorInfoPins)
        emit sigQueryPin(paramMacAddr);
}

void    StatusOperation::insertAddrTTLMap(qint64 addr, qint16 TTL)
{
    addrTTLMap.insert(addr,TTL);
}

void    StatusOperation::removeAddrTTLMap(qint64 addr)
{
    addrTTLMap.remove(addr);
}

void    StatusOperation::updateAddrTTLMap(qint64 addr, qint16 TTL)
{
    addrTTLMap.insert(addr,TTL);  //原先的item将被替换
}

void StatusOperation::updateAddrSensorTTLMap(QByteArray baMacAddr,qint16 TTL)
{
    addrSensorTTLMap.insert(baMacAddr,TTL);
}


void    StatusOperation::doWithMac( qint64 &macAddr)
{
    if(macAddr<=0)
        return;

    if(sourceV4IP.count(".")!=3)
        return;
    //节点处于alive状态，更新一下addrSocketMap，因为可能端口发生了变化
    if(addrTTLMap.contains(macAddr)&&addrSocketMap.contains(macAddr))
    {
        addrSocketMap.insert(macAddr,sourceV4IP.toLatin1()+":"+QString::number(sourcePort));
        return;
    }

    //用"TBD"+mac地址作为待命名的节点名.如果节点已经注册过名字，则忽略
    QByteArray nodeName="TBD"+QByteArray::number(macAddr,10);
    addrSocketMap.insert(macAddr,sourceV4IP.toLatin1()+":"+QString::number(sourcePort));
    newMacList.append(macAddr);
    insertAddrTTLMap(macAddr,TTL_MAX);
    QByteArray nodeType;
    if(sourceV4IP.toLatin1()!="127.0.0.1")
        nodeType="ARM";
    else if(sourcePort==dataBaseComUdpPort)
        nodeType="CC2530";
    else
        nodeType="5139";

    parentWeathSta->slotShowErrorInfo(tr("即将发射信号sigRegNode"));

    emit sigRegNode(macAddr,nodeName,1,sourceV4IP.toLatin1(),sourcePort,nodeType,curHexProtocHead,0);
}

void StatusOperation::doWithSensor(qint64 macAddr, quint8 sensorID)
{
    QByteArray baAddrSensor=QByteArray::number(macAddr,10)+":"+QByteArray::number(sensorID,10);

    addrSensorTTLMap.insert(baAddrSensor,TTL_MAX);
    parentWeathSta->slotShowErrorInfo(tr("即将发射信号sigRegSensor"));
    emit sigRegSensor(macAddr,sensorID,1);
}

/*
  考虑虚拟节点，出现节点expire时，删除addrSockeMap等中的记录，但是，不更新数据库中的相关内容。
  只有当addrTTLMap中，没有和这个虚拟节点后7字节相同的节点时，才更新数据库内容
  */
void    StatusOperation::doWithExpiredMac(qint64 addr)
{
    if(addr<=0)
        return;

    //在addrSocketMap表中删除该项
    addrSocketMap.remove(addr);

    newMacList.removeOne(addr);
    removeAddrTTLMap(addr);

    emit sigRemoveOneInControllingMacList(QString::number(addr));

    qint64 mask= Q_INT64_C(0x00ffffffffffffff);
    qint64 subAddr=addr&mask;
    QList <qint64> listAliveSubAddr=addrTTLMap.keys();
    for(int n=0;n<listAliveSubAddr.size();n++)
    {
        if(subAddr==(listAliveSubAddr.at(n)&mask))
            return;
    }

    emit sigUnRegNode(subAddr);
}

void StatusOperation::doWithExpiredSensor(qint64 addr, quint8 sensorID)
{
    QByteArray baAddrSensor=QByteArray::number(addr,10)+":"+QByteArray::number(sensorID,10);

    addrSensorTTLMap.remove(baAddrSensor);
    emit sigUnRegSensor(addr,sensorID,0);
}

void    StatusOperation::doWithSensorInfo(QByteArray &data, qint64 macAddr)
{
#ifdef DEBUG
    qDebug()<<"macaddress in dowith sensorinfo is"<<macAddr;
#endif
    quint8 senSorID;

    if(sourceV4IP.count(".")!=3)
        return;
    //更新一下addrSocketMap，因为此时可能路由器给节点分配了不同的断开
    addrSocketMap.insert(macAddr,sourceV4IP.toLatin1()+":"+QString::number(sourcePort));

    QByteArray sensorIDByte=data.mid(0,1);
    bool ok;
    senSorID=sensorIDByte.toHex().toUInt(&ok,16);

    emit sigRegSensor(macAddr,senSorID,1);
    QByteArray datagram2BeSent;


    if(senSorID==11)
    {
        parentWeathSta->clientIP=aServerIP;
        datagram2BeSent="Mac "+ QByteArray::number(macAddr,10)+" 1  CmdNrm  VideoHik_RealPlayStart";
        parentWeathSta->analyzeIncomeDatagram(datagram2BeSent);

    }
    if(senSorID==12)
    {
        parentWeathSta->clientIP=aServerIP;
        datagram2BeSent="Mac "+ QByteArray::number(macAddr,10)+" 1  CmdNrm  VideoMJPEG_RealPlayStart";
        parentWeathSta->analyzeIncomeDatagram(datagram2BeSent);
    }
    if(senSorID==13)
    {
        parentWeathSta->clientIP=aServerIP;
        datagram2BeSent="Mac "+QByteArray::number(macAddr,10)+" 1  CmdNrm  Video264_RealPlayStart";
        parentWeathSta->analyzeIncomeDatagram(datagram2BeSent);
    }
}


/*******初始化定时器*********/
void StatusOperation::initTimer()
{
    QTime currentTime=QTime::currentTime();
    int timeTo;
    timeTo=currentTime.secsTo(QTime(23,59,59,999));

    int timeToZero;
    timeToZero=currentTime.msecsTo(QTime(0,0,5,0));

    if(timeToZero>0) //00:00:00以后，00:00:05之前
    {
        timer->start(msForUpdate);
    }
    else if(timeTo>60*31) //23:29前
        timer->start(msForUpdate);
    else
        timer->start(currentTime.msecsTo(QTime(23,59,59,999))+2000); //00:00:01触发

}

void StatusOperation::myTimerEvent()
{
    /******更新计时器****/
    QTime currentTime=QTime::currentTime();
    int timeTo;
    timeTo=currentTime.secsTo(QTime(23,59,59,999));
    int timeToZero;
    timeToZero=currentTime.msecsTo(QTime(0,0,5,0));

    if(timeToZero>0) //00:00:00以后，00:00:05之前
    {
        timer->start(msForUpdate);
        tableNamePrefix=QDate::currentDate().toString("'multi'yyyy_MM_dd_'mac'").toLatin1();
        tableNameList.clear(); //清除过期的表名list
    }

    else if(timeTo>60*31) //23:29前
        timer->start(msForUpdate);
    else
        timer->start(currentTime.msecsTo(QTime(23,59,59,999))+2000); //00:00:00以后触发，500ms裕量
}

void StatusOperation::timerEventForTTL()
{
    QMapIterator<qint64,qint16> i(addrTTLMap);  //遍历整个map
    while (i.hasNext())
    {
        i.next();
        if(i.value()<=0) //该TTL过期
        {            
            doWithExpiredMac(i.key()); //作相应处理
        }
        else
            updateAddrTTLMap(i.key(),i.value()-20); //由于20s调用一次该函数，所以需要减去20
    }

    QMapIterator<QByteArray,qint16> i2(addrSensorTTLMap);  //遍历整个map
    while (i2.hasNext())
    {
        i2.next();
        if(i2.value()<=0) //该TTL过期
        {
            QList <QByteArray> listAddrSensor=i2.key().split(':');
            if(listAddrSensor.size()==2)
            {
                qint64 macAddr=listAddrSensor.at(0).toLongLong();
                quint8 sensorID=listAddrSensor.at(1).toUInt();
                doWithExpiredSensor(macAddr,sensorID); //作相应处理
            }
        }
        else
            addrSensorTTLMap.insert(i2.key(),i2.value()-20); //由于20s调用一次该函数，所以需要减去20
    }
}


/******把当天建立的表的表名存储于list**********/
void StatusOperation::initTableNameList()
{
    int timeToZero;
    timeToZero=QTime::currentTime().msecsTo(QTime(23,59,59,999));
    if(timeToZero<500) //00:00:00以后，00:00:05之前
    {
#ifndef ANDROID
        Sleep(timeToZero+100);
#endif

    }
    QSqlQuery querySQLTemp(QSqlDatabase::database(DB_CON_NAME_WEATHERSTATION));

    QString currentDate=QDate::currentDate().toString("yyyyMMdd");
    if(querySQLTemp.exec("select  TableName,NodeMacAddr,SensorID from MultiDataIndex where DateTimeStart"
        ">="+currentDate) )
    {
        //qint64  addr;
        //quint8 sensorID;
        //bool ok;
        while(querySQLTemp.next())
        {
            tableNameList.append(querySQLTemp.value(0).toString());
            //addr=queryTemp->value(1).toULongLong(&ok);
            //sensorID=queryTemp->value(2).toUInt(&ok);
            //((WeatherStation*)parent())->myP2pServer->addVideoSource(
               //     QHostAddress(aServerIP),aServerPort,addr,sensorID);
        }
    }
    tableNamePrefix=QDateTime::currentDateTime().toString("'multi'yyyy_MM_dd_'mac'").toLatin1();
}

void    StatusOperation::setSensorOnWorkInNodeSenMap(qint64 mac, quint8 sensorID)
{
    QSqlQuery querySQLTemp(QSqlDatabase::database(DB_CON_NAME_WEATHERSTATION));

    if(querySQLTemp.exec("update NodeSensorMap set SensorOnWork=1 "
         "where NodeMacAddress="+QString::number(mac,10)+
         " and SensorID="+QString::number(sensorID,10)) )
    {

    }
    else
    {
        qDebug()<<"fail in StatusOperation::setSensorOnWorkInNodeSenMap"<<querySQLTemp.lastError();
        ((WeatherStation*)parent())->dbo->insertLog("fail in StatusOperation::setSensorOnWorkInNodeSenMap"
              +querySQLTemp.lastError().text());
    }

}

